package com.kgcx.order.controller;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.github.pagehelper.PageHelper;
import com.kgcx.common.annotation.validator.IdValidator;
import com.kgcx.common.api.ApiContant;
import com.kgcx.common.bean.RequestData;
import com.kgcx.common.bean.ReturnData;
import com.kgcx.common.client.coupon.CouponClient;
import com.kgcx.common.client.coupon.pojo.Coupon;
import com.kgcx.common.client.order.OrderClient;
import com.kgcx.common.client.organization.DriverClient;
import com.kgcx.common.client.organization.pojo.Driver;
import com.kgcx.common.client.price.MileageLocationClient;
import com.kgcx.common.client.price.pojo.MileageRecord;
import com.kgcx.common.constant.Cons;
import com.kgcx.common.constant.ResultCode;
import com.kgcx.common.controller.BaseController;
import com.kgcx.common.eum.OrderCancelTypeEnum;
import com.kgcx.common.eum.OrderEnum;
import com.kgcx.common.rabbitmq.bean.Message;
import com.kgcx.common.rabbitmq.consts.ExchangeConst;
import com.kgcx.common.rabbitmq.consts.RoutingKeyConst;
import com.kgcx.common.utils.*;
import com.kgcx.core.utils.HelpUtil;
import com.kgcx.core.utils.JsonUtil;
import com.kgcx.dbutils.annotation.service.CityValidator;
import com.kgcx.dbutils.domain.Region;
import com.kgcx.dbutils.service.DictService;
import com.kgcx.order.client.BookParame;
import com.kgcx.order.client.ScheduleClient;
import com.kgcx.order.common.MqttProducerUtil;
import com.kgcx.order.common.Util;
import com.kgcx.order.domain.*;
import com.kgcx.order.entity.HotAddress;
import com.kgcx.order.entity.OrderChangeMessage;
import com.kgcx.order.mapper.OrderDriverMapper;
import com.kgcx.order.mapper.OrderDriverPaiedMapper;
import com.kgcx.order.service.*;
import com.kgcx.order.vo.DriverPayingOrder;
import com.kgcx.order.vo.UserMileage;
import com.xiaoleilu.hutool.date.DatePattern;
import com.xiaoleilu.hutool.date.DateUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;


/**
 * Created by Paul on 2017/11/8.
 */
@Api(description = "订单接口", tags = "订单接口")
@RestController
@RequestMapping("order")
public class OrderController extends BaseController {
    private static final Logger LOG = LoggerFactory.getLogger(OrderController.class);
    @Autowired
    private OrderService service;
    @Autowired
    private OrderLogService oLogService;
    @Autowired
    private OrderDriverMapper odMapper;
    @Autowired
    private OrderDriverPaiedMapper odpMapper;
    @Autowired
    private DriverClient driverClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private StringRedisTemplate strRedisTemplate;
    @Autowired
    private MqttProducerUtil mqttService;
    @Autowired
    private OrderNotifyDriverService orderNotifyDriverService;
    @Autowired
    private OrderClient orderClient;
    @Autowired
    private OrderDriverService orderDriverService;
    @Resource
    private PayService payService;
    @Autowired
    private CouponClient couponClient;
    @Autowired
    private ScheduleClient scheduleClient;
    @Autowired
    private DictService dictService;

    @Autowired
    private MileageLocationClient mileageLocationClient;

    @ApiImplicitParams({
            @ApiImplicitParam(name = "placing_user_id", value = "下单人ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "placing_user_phone", value = "下单人电话", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "passenger_phone", value = "乘车人电话", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "is_notify", value = "是否短信通知(1-是，2-否)", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "is_self", value = "是否自己乘车(1-自己，2-他人)", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "airport_id", value = "机场ID", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "station_id", value = "高铁站ID", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "order_channel", value = "订单渠道", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "plan_orig_city_id", value = "计划出发城市id", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "plan_orig", value = "计划出发地", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_orig_lng", value = "计划出发地经度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_orig_lat", value = "计划出发地纬度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_dest", value = "计划到达地", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_dest_lng", value = "计划到达城市经度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_dest_lat", value = "计划到达城市纬度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_mileage", value = "预估里程", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "plan_price", value = "预估价格", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "plan_duration", value = "预估时长", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "order_type", value = "订单类型", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "model", value = "车辆类型", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "couponId", value = "优惠卷id", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "fare_type", value = "计价类型", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "mac", value = "mac", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "imei", value = "imei", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "imsi", value = "imsi", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)

    })
    @ApiOperation(value = "通用 - 立即创建订单", httpMethod = "POST", notes = "立即创建订单，返回订单号")
    @PostMapping("createOrder")
    @CityValidator(name = "plan_orig_city_id")
    public ReturnData<String> createOrder(@RequestParam(required = false, name = "placing_user_id") Long placingUserId,
                                          @RequestParam(required = false, name = "placing_user_phone") String placingUserPhone,
                                          @RequestParam(required = false, name = "passenger_phone") String passengerPhone,
                                          @RequestParam(required = true, name = "is_self") Integer isSelf,
                                          @RequestParam(required = false, name = "is_notify") Integer isNotify,
                                          @RequestParam(required = false, name = "airport_id") Long airportId,
                                          @RequestParam(required = false, name = "station_id") Long stationId,
                                          @RequestParam(required = true, name = "order_channel") Integer orderChannel,
                                          @RequestParam(required = true, name = "plan_orig_city_id") Integer planOrigCityId,
                                          @RequestParam(required = true, name = "plan_orig") String planOrig,
                                          @RequestParam(required = true, name = "plan_orig_lng") String planOrigLng,
                                          @RequestParam(required = true, name = "plan_orig_lat") String planOrigLat,
                                          @RequestParam(required = true, name = "plan_dest") String planDest,
                                          @RequestParam(required = true, name = "plan_dest_lng") String planDestLng,
                                          @RequestParam(required = true, name = "plan_dest_lat") String planDestLat,
                                          @RequestParam(required = false, name = "plan_mileage") Long planMileage,
                                          @RequestParam(required = false, name = "plan_price") Integer planPrice,
                                          @RequestParam(required = false, name = "plan_duration") Integer planDuration,
                                          @RequestParam(required = false, name = "couponId") Integer couponId,
                                          @RequestParam(required = true, name = "order_type") Integer orderType,
                                          @RequestParam(required = true, name = "model") Integer model,
                                          @RequestParam(required = true, name = "fare_type") Integer fareType,
                                          @RequestParam(required = false, name = "mac") String mac,
                                          @RequestParam(required = false, name = "imei") String imei,
                                          @RequestParam(required = false, name = "imsi") String imsi) {

        String userOrdersPendingPayKey = Util.getUserOrdersPendingPayKey(placingUserId);
        String userOrdersOngoingKey = Util.getUserOrdersOngoingKey(placingUserId);
        ReturnData<String> returnData = new ReturnData<>();

        //1.1 检查是否有未支付订单
        long size = strRedisTemplate.opsForSet().size(userOrdersPendingPayKey);
//        strRedisTemplate.opsForHash().get(OrderEnum.ORDERS_USER, user_orders_ongoing_key);
        if (size >= 1) {
            returnData.setData(strRedisTemplate.opsForSet().members(userOrdersPendingPayKey).iterator().next());
            returnData.setCode(ResultCode.HAS_ORDER_PENDING_PAY);
            returnData.setMsg("下单失败，有未支付的订单");
            return returnData;
        }

        //1.2 检查是否有未完成订单
        size = strRedisTemplate.opsForList().size(userOrdersOngoingKey);
        if (size >= 2) { //大于2单不可以继续下单
            returnData
                    .setData(JsonUtil.toString(strRedisTemplate.opsForList().range(userOrdersOngoingKey, 0, -1)));
            returnData.setCode(ResultCode.HAS_ORDER_ONGOING);
            returnData.setMsg("下单失败，有超过两单未完成订单");
            return returnData;
        }

        //2.检查通过后继续下单流程
        Order record = new Order();
        try {

            record.setOrderNo(UUIDUtils.getOrderSnByTime18());
            record.setPlacingUserId(placingUserId);
            record.setPlacingUserPhone(placingUserPhone);
            record.setPassengerPhone(passengerPhone);
            record.setIsSelf(isSelf);
            record.setOrderChannel(orderChannel);
            record.setPlanOrigCityId(planOrigCityId);
            record.setPlanOrig(planOrig);
            record.setPlanOrigLng(planOrigLng);
            record.setPlanOrigLat(planOrigLat);
            record.setPlanDestCityId(0);
//            record.setPlanDest(URLDecoder.decode(plan_dest, "UTF-8"));
            record.setPlanDest(planDest);
            record.setPlanDestLng(planDestLng);
            record.setPlanDestLat(planDestLat);
            record.setPlanMileage(planMileage);
            record.setPlanDuration(planDuration);
            record.setPlanPrice(planPrice);
            record.setOrderType(orderType);
            record.setBookModel(model);
            record.setFareType(fareType);
            record.setPlanDepartTime(new Timestamp(System.currentTimeMillis()));
            record.setOrderState(OrderEnum.WAIT_ORDER);
            record.setCreateId(placingUserId);
            record.setCreateTime(new Timestamp(System.currentTimeMillis()));
            record.setStatus(Cons.COMMON_STATUS_ACTIVE);
            record.setPayType(OrderEnum.PAY_TYPE_USER); //默认乘客支付
            record.setAirportId(airportId);
            record.setStationId(stationId);
            record.setIsNotify(isNotify == null ? 2 : isNotify);
            record.setCouponId(couponId);
            record.setMac(mac);
            record.setImei(imei);
            record.setImsi(imsi);
            record.setIp(IpUtils.getIpAddr(getRequest()));
            record.setPort(String.valueOf(getRequest().getRemotePort()));
        } catch (Exception ex) {
            LOG.error("接收参数异常", ex);
        }

        String recordStr = JsonUtil.toString(record);
        try {
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, record.getOrderNo(), recordStr);
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_STATUS, record.getOrderNo(),
                    String.valueOf(record.getOrderState()));
            service.addToUserOrdersOngoing(record);
        } catch (Exception e) {
            e.printStackTrace();
        }

        LOG.info(String.format("发送创建立即订单成功的消息，订单内容：[%s]。", JsonUtil.toString(record)));
        rabbitTemplate.convertAndSend(OrderEnum.ORDER_EXCHANGE, "kgcx.order.create", recordStr);

        // 给监管平台发消息
        LOG.info(String.format("创建订单成功的MQ消息，订单号[%s]。", record.getOrderNo()));
        Message msg = Message.buildMessage(ApiContant.ORDER_CREATE, Message.FLAG_ADD, record);
        rabbitTemplate.convertAndSend(ExchangeConst.OPC, RoutingKeyConst.OPC_COMMON, JSONObject.toJSONString(msg));

        returnData.setData(record.getOrderNo());
        returnData.setCode(ResultCode.SUCCESS);
        returnData.setMsg("success");
        return returnData;
    }


    @ApiOperation(value = "通用 - 预约创建订单", httpMethod = "POST", notes = "预约创建订单，返回订单号")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "placing_user_id", value = "下单人ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "placing_user_phone", value = "下单人电话", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "passenger_phone", value = "乘车人电话", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "is_notify", value = "是否短信通知(1-是，2-否)", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "is_self", value = "是否自己乘车(1-自己，2-他人)", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "airport_id", value = "机场ID", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "station_id", value = "高铁站ID", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "order_channel", value = "订单渠道", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "plan_orig_city_id", value = "计划出发城市id", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "plan_orig", value = "计划出发地", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_orig_lng", value = "计划出发地经度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_orig_lat", value = "计划出发地纬度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_dest", value = "计划到达", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_dest_lng", value = "计划到达城市经度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_dest_lat", value = "计划到达城市纬度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "plan_mileage", value = "预估里程", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "plan_price", value = "预估价格", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "plan_duration", value = "预估时长", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "order_type", value = "订单类型", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "model", value = "车辆类型", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "fare_type", value = "计价类型", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "plan_depart_time", value = "计划出发时间", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "couponId", value = "优惠卷id", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "flight_info", value = "航票信息", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "mac", value = "mac", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "imei", value = "imei", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "imsi", value = "imsi", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)

    })
    @PostMapping("planCreateOrder")
    @CityValidator(name = "plan_orig_city_id")
    public ReturnData planCreateOrder(@RequestParam(required = true, name = "placing_user_id") Long placingUserId,
                                      @RequestParam(required = false, name = "placing_user_phone") String placingUserPhone,
                                      @RequestParam(required = false, name = "passenger_phone") String passengerPhone,
                                      @RequestParam(required = false, name = "is_notify") Integer isNotify,
                                      @RequestParam(required = true, name = "is_self") Integer isSelf,
                                      @RequestParam(required = false, name = "airport_id") Long airportId,
                                      @RequestParam(required = false, name = "station_id") Long stationId,
                                      @RequestParam(required = true, name = "order_channel") Integer orderChannel,
                                      @RequestParam(required = true, name = "plan_orig_city_id") Integer planOrigCityId,
                                      @RequestParam(required = true, name = "plan_orig") String planOrig,
                                      @RequestParam(required = true, name = "plan_orig_lng") String planOrigLng,
                                      @RequestParam(required = true, name = "plan_orig_lat") String planOrigLat,
                                      @RequestParam(required = true, name = "plan_dest") String planDest,
                                      @RequestParam(required = true, name = "plan_dest_lng") String planDestLng,
                                      @RequestParam(required = true, name = "plan_dest_lat") String planDestLat,
                                      @RequestParam(required = false, name = "plan_mileage") Long planMileage,
                                      @RequestParam(required = false, name = "plan_price") Integer planPrice,
                                      @RequestParam(required = false, name = "plan_duration") Integer planDuration,
                                      @RequestParam(required = true, name = "order_type") Integer orderType,
                                      @RequestParam(required = true, name = "model") Integer model,
                                      @RequestParam(required = false, name = "couponId") Integer couponId,
                                      @RequestParam(required = true, name = "fare_type") Integer fareType,
                                      @RequestParam(required = true, name = "plan_depart_time") Long planDepartTime,
                                      @RequestParam(required = false, name = "flight_info") String flightInfo,
                                      @RequestParam(required = false, name = "mac") String mac,
                                      @RequestParam(required = false, name = "imei") String imei,
                                      @RequestParam(required = false, name = "imsi") String imsi) {

        long time = System.currentTimeMillis();

        String userOrdersPendingPayKey = Util.getUserOrdersPendingPayKey(placingUserId);
        String userOrdersOngoingKey = Util.getUserOrdersPlanOngoingKey(placingUserId);
        ReturnData<String> returnData = new ReturnData<>();

        //1.1 检查是否有未支付订单
        long size = strRedisTemplate.opsForSet().size(userOrdersPendingPayKey);
//        strRedisTemplate.opsForHash().get(OrderEnum.ORDERS_USER, userOrdersOngoingKey);
        if (size >= 1) {
            returnData.setData(strRedisTemplate.opsForSet().members(userOrdersPendingPayKey).iterator().next());
            returnData.setCode(ResultCode.HAS_ORDER_PENDING_PAY);
            returnData.setMsg("下单失败，有未支付的订单");
            return returnData;
        }

        //1.2 检查是否有未完成订单
        size = strRedisTemplate.opsForList().size(userOrdersOngoingKey);
        if (size >= 2) { //大于2单不可以继续下单
            returnData
                    .setData(JsonUtil.toString(strRedisTemplate.opsForList().range(userOrdersOngoingKey, 0, -1)));
            returnData.setCode(ResultCode.HAS_ORDER_ONGOING);
            returnData.setMsg("下单失败，有超过两单未完成订单");
            return returnData;
        }

        //1.3 判断下单时间是否满足最大最小预约时间
        Map<String, BookParame> dataMap = scheduleClient.getBookParame(Long.valueOf(planOrigCityId));
        //计算下单时间与计划出发时间相差的天数
        float d = (float) (planDepartTime - time) / (float) (1000 * 3600 * 24);
        if (d <= 0) {
            returnData
                    .setData(HelpUtil.formatDatetime(planDepartTime));
            returnData.setCode(ResultCode.SYSTEM_TIME_ERROR);
            returnData.setMsg("预约失败，请检查系统时间是否准确");
            return returnData;
        }
        int day = (int) d;
        if ((planDepartTime - time) % (1000 * 3600 * 24) > 0) {
            day++;
        }
        //计算下单时间与计划出发时间相差的分钟数
        float min = (float) (planDepartTime - time) / (float) (1000 * 60);
        //预约接机
        if (orderType == 3 && (dataMap.get("speciallyPickPlanBook").getMax_time() < day)) {
            returnData
                    .setData(HelpUtil.formatDatetime(planDepartTime));
            returnData.setCode(ResultCode.PLAN_TIME_ERROR);
            returnData.setMsg("预约失败，计划上车时间不满足系统要求");
            return returnData;
        }
        //预约接站
        if (orderType == 4 && (dataMap.get("speciallyPickTrainBook").getMax_time() < day)) {
            returnData
                    .setData(HelpUtil.formatDatetime(planDepartTime));
            returnData.setCode(ResultCode.PLAN_TIME_ERROR);
            returnData.setMsg("预约失败，计划上车时间不满足系统要求");
            return returnData;
        }
        //预约送机
        if (orderType == 5 && (dataMap.get("optionallySendPlanBook").getMax_time() < day || dataMap.get("optionallySendPlanBook").getMin_time() > min)) {
            returnData
                    .setData(HelpUtil.formatDatetime(planDepartTime));
            returnData.setCode(ResultCode.PLAN_TIME_ERROR);
            returnData.setMsg("预约失败，计划上车时间不满足系统要求");
            return returnData;
        }
        //预约送站
        if (orderType == 6 && (dataMap.get("optionallySendTrainBook").getMax_time() < day || dataMap.get("optionallySendTrainBook").getMin_time() > min)) {
            returnData
                    .setData(HelpUtil.formatDatetime(planDepartTime));
            returnData.setCode(ResultCode.PLAN_TIME_ERROR);
            returnData.setMsg("预约失败，计划上车时间不满足系统要求");
            return returnData;
        }
        //预约用车
        if (orderType == 7 && (dataMap.get("optionallyBook").getMax_time() < day || dataMap.get("optionallyBook").getMin_time() > min)) {
            returnData
                    .setData(HelpUtil.formatDatetime(planDepartTime));
            returnData.setCode(ResultCode.PLAN_TIME_ERROR);
            returnData.setMsg("预约失败，计划上车时间不满足系统要求");
            return returnData;
        }

        //1.4判断当前时段预约运力是否已满
        if (!((orderType == 3 && dataMap.get("speciallyPickPlanBook").getMin_time() > min)
                || (orderType == 4 && dataMap.get("speciallyPickTrainBook").getMin_time() > min))) {
            Boolean aBoolean = scheduleClient.checkRecord(orderType, Long.valueOf(planOrigCityId), model, planDepartTime);
            if (!aBoolean) {
                returnData
                        .setData(HelpUtil.formatDatetime(planDepartTime));
                returnData.setCode(ResultCode.BOOK_CAPACITY_NOT_ENOUGH);
                returnData.setMsg("下单失败，当前时段预约运力已满");
                return returnData;
            }
        }

        //2.检查通过后继续下单流程
        Order record = new Order();
        try {
            if ((orderType == 3 && dataMap.get("speciallyPickPlanBook").getMin_time() > min)
                || (orderType == 4 && dataMap.get("speciallyPickTrainBook").getMin_time() > min)) {
                record.setOrderState(OrderEnum.WAIT_ORDER);
            }else {
                record.setOrderState(OrderEnum.PLAN_SUCCESS);
            }
            record.setOrderNo(UUIDUtils.getOrderSnByTime18());
            record.setPlacingUserId(placingUserId);
            record.setPlacingUserPhone(placingUserPhone);
            record.setPassengerPhone(passengerPhone);
            record.setIsSelf(isSelf);
            record.setOrderChannel(orderChannel);
            record.setPlanOrigCityId(planOrigCityId);
            record.setPlanOrig(planOrig);
            record.setPlanOrigLng(planOrigLng);
            record.setPlanOrigLat(planOrigLat);
            record.setPlanDestCityId(0);
            record.setPlanDest(planDest);
            record.setPlanDestLng(planDestLng);
            record.setPlanDestLat(planDestLat);
            record.setPlanMileage(planMileage);
            record.setPlanDuration(planDuration);
            record.setPlanPrice(planPrice);
            record.setOrderType(orderType);
            record.setBookModel(model);
            record.setFareType(fareType);
            record.setCreateId(placingUserId);
            record.setCreateTime(new Timestamp(time));
            record.setStatus(Cons.COMMON_STATUS_ACTIVE);
            record.setPayType(OrderEnum.PAY_TYPE_USER); //默认乘客支付
            record.setPlanDepartTime(new Timestamp(planDepartTime));
            record.setFlightInfo(flightInfo);
            record.setAirportId(airportId);
            record.setStationId(stationId);
            record.setIsNotify(isNotify == null ? 2 : isNotify);
            record.setCouponId(couponId);
            record.setMac(mac);
            record.setImei(imei);
            record.setImsi(imsi);
            record.setIp(IpUtils.getIpAddr(getRequest()));
            record.setPort(String.valueOf(getRequest().getRemotePort()));
        } catch (Exception ex) {
            LOG.error("接收参数异常", ex);
        }
        String recordStr = JsonUtil.toString(record);
        try {
//            jsonRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, record.getOrderNo() + "1", record);
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, record.getOrderNo(), recordStr);
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_STATUS, record.getOrderNo(),
                    String.valueOf(record.getOrderState()));
            strRedisTemplate.opsForList().leftPush(userOrdersOngoingKey, record.getOrderNo());

        } catch (Exception e) {
            e.printStackTrace();
        }

        LOG.info(String.format("发送创建预约订单成功的消息，订单内容：[%s]。", JsonUtil.toString(record)));
        rabbitTemplate.convertAndSend(OrderEnum.ORDER_EXCHANGE, "kgcx.order.create", recordStr);


        // 给监管平台发消息
        LOG.info(String.format("创建订单成功的MQ消息，订单号[%s]。", record.getOrderNo()));
        Message msg = Message.buildMessage(ApiContant.ORDER_CREATE, Message.FLAG_ADD, record);
        rabbitTemplate.convertAndSend(ExchangeConst.OPC, RoutingKeyConst.OPC_COMMON, JSONObject.toJSONString(msg));

        returnData.setData(record.getOrderNo());
        returnData.setCode(ResultCode.SUCCESS);
        returnData.setMsg("success");
        return returnData;
    }


    @ApiOperation(value = "通用 - 查询订单", httpMethod = "GET", notes = "查询单条订单详情")
    @ApiImplicitParams(
            @ApiImplicitParam(name = "order_no", value = "订单号", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class)
    )
    @GetMapping("getByOrderNo")
    public ReturnData<Order> getByOrderNo(@RequestParam(name = "order_no") String orderNo) {

//        1.先从redis中取
        Order order = service.getIngOrderByOrderNo(orderNo);
        if (order == null) {
            //2. redis中没有的话，从数据库取
            order = service.getByOrderNo(orderNo);
        }
        if (order != null && !validateTokenId(order.getDriverId(), order.getPlacingUserId())) {
            return ReturnData.NO_PERMISSION;
        }
        return new ReturnData<>(order);
    }

    @ApiOperation(value = "乘客 - 查询订单状态", httpMethod = "GET", notes = "查询订单状态（1-等待接单，2-预约成功，3-已派车，4-司机出发，5-司机到达出发地，6-乘客已上车，7-行程中，8-行程结束待计算价格，9-行程结束待付款，10-标注已付款（用于司机代付），11-已支付（确实已付款，来自支付渠道的返回结果），12-已评价，13-已取消，14-派车失败订单失败，15-运力不足订单失败，20-已关闭）")
    @ApiImplicitParams(
            @ApiImplicitParam(name = "order_no", value = "订单号", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class)
    )
    @GetMapping("getOrderState")
    public ReturnData<Integer> getOrderState(@RequestParam(name = "order_no") String orderNo) {
        RequestData requestData = this.getRequestData();
        ReturnData rtnData = new ReturnData();
        Order itm;
//        1.先从redis中取
        Object obj = strRedisTemplate.opsForHash()
                .get(OrderEnum.ORDERS_STATUS, orderNo);
        if (obj != null) {
            rtnData.setData(obj.toString());
        } else {
            //2. redis中没有的话，从数据库取
            itm = service.getByOrderNo(orderNo);
            if (itm != null) {
                rtnData.setData(itm.getOrderState());
            } else {
                rtnData.setMsg(String.format("未找到订单，订单号：{%s}", orderNo));
                LOG.error("【获取订单状态】未找到订单：" + orderNo);
            }
        }
        return rtnData;
    }

    //查询订单列表
    @ApiOperation(value = "查询订单列表", httpMethod = "GET", notes = "查询订单列表"
    )
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderBy", value = "排序", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "status", value = "状态(1-已完成，2-进行中)", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "user_id", value = "user_id", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping("list")
    @IdValidator(value = {"user_id", "driver_id"})
    public ReturnData<List<Order>> list(@RequestParam Integer status,
                                        @RequestParam(required = false, name = "driver_id") Long driverId,
                                        @RequestParam(required = false, name = "user_id") Long userId) {
        RequestData requestData = this.getRequestData();
        List<Order> list = new ArrayList<>();

        if (status.equals(OrderEnum.FINISHED)) {
            if (driverId != null && driverId > 0) {
                //todo 过滤
                list = service.list(requestData, driverId, 0L, null);
                try {
                    list.sort((o1, o2) -> o2.getDestTime().compareTo(o1.getDestTime()));
                } catch (Exception ex) {
                    LOG.error("订单排序异常，有完成订单dest_time为null", ex);
                }
            } else if (userId != null && userId > 0) {
                //todo 过滤
                list = service.list(requestData, 0L, userId, null);
            } else {
                list = service.list(requestData, 0L, 0L, null);
            }
        } else if (status.equals(OrderEnum.ONGOING)) {
            List<Order> orders = service.listIngOrders();
            for (Order order : orders) {
                if (driverId != null && driverId > 0) {
                    if (order.getDriverId() != null && order.getDriverId().equals(driverId)) {
                        list.add(order);
                    }
                } else if (userId != null && userId > 0) {
                    if (order.getPlacingUserId() != null && order.getPlacingUserId().equals(userId)) {
                        list.add(order);
                    }
                } else {
                    list.add(order);
                }
            }
        }
        return new ReturnData<>(list);
    }

    //订单状态切换/开始订单
    @ApiOperation(value = "通用 - 订单状态切换", httpMethod = "POST", notes = "订单状态切换")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "order_no", value = "订单编号", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "order_state", value = "订单状态，1-等待接单，2-预约成功，3-已派车，4-司机出发，5-司机到达出发地，6-乘客已上车，7-行程中，8-行程结束待计算价格，9-行程结束待付款，10-标注已付款（用于司机代付），11-已支付（确实已付款，来自支付渠道的返回结果），12-已评价，13-已取消，14-派车失败订单失败，15-运力不足订单失败，20-已关闭", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),

    })
    @PostMapping("stateSwitch")
    public ReturnData stateSwitch(@RequestParam(name = "order_no") String orderNo,
                                  @RequestParam(name = "order_state") Integer orderState) {

        ReturnData rtnData = new ReturnData();
        //todo 状态变化逻辑待完善
        // 一、先从redis中找订单
        Order order = service.getIngOrderByOrderNo(orderNo);
        if (order != null) {
            //只有支付时用户取消了支付才能让状态回滚到待支付，其他节点一律不允许状态往回走
            boolean isPayBack = order.getOrderState() == 30 && (orderState == 9 || orderState == 10);
            if (!isPayBack && orderState < order.getOrderState()) {
                return new ReturnData<>("-1", String.format("状态修改错误,无法从【%d】变成【%d】", order.getOrderState(), orderState));
            }
            //更新操作
            LOG.info(String.format("修改进行中的订单状态，订单【%s】状态从【%d】变成【%d】。", orderNo, order.getOrderState(), orderState));
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_STATUS, orderNo, String.valueOf(orderState));
            order.setOrderState(orderState);
            // 必须要加，更新为当前时间
            order.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            //begin updata 何凯 订单进行中不包含14 派车失败
            if (orderState.equals(OrderEnum.AUTO_DISPATCH_FAIL)) {
                strRedisTemplate.opsForHash().delete(OrderEnum.ORDERS_ING, orderNo, JsonUtil.toString(order));
                //从用户订单列表中删除
                service.removeFromUserOrdersOngoing(order);
                service.add(order);
            } else {
                strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, orderNo, JsonUtil.toString(order));
            }
            //end updata 何凯


            //到达目的地，更新订单状态、到达时间
            if (orderState.equals(OrderEnum.ARRIVED_PENDING_PRICE)) {
                order.setDestTime(new Timestamp(System.currentTimeMillis()));
                order.setOrderState(OrderEnum.ARRIVED_PENDING_PRICE);
                order.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, orderNo, JsonUtil.toString(order));
            }

            //给乘客发送当前订单状态消息
            OrderChangeMessage mqMsg = new OrderChangeMessage(order.getOrderNo()
                    , orderState, null, "stateSwitch", order.getPlacingUserId());
            service.sendMqtt(JsonUtil.toString(mqMsg)
                    , OrderEnum.ORDER_STATE_TOPIC + "." + order.getPlacingUserId());

            oLogService.log(order, "redis更新订单, orderState = " + orderState);
            rtnData.setCode(ResultCode.SUCCESS);
            rtnData.setMsg("状态变更为:" + orderState);
            return rtnData;

        } else {
            //二、redis中没找到订单，则从数据库中取（一般只有乘客评价改状态才会走进这里）
            order = service.getByOrderNo(orderNo);
            if (order != null) {
                if (order.getOrderState().equals(OrderEnum.MARKED_PAIED) && orderState.equals(OrderEnum.USER_PAYING)) {
                    rtnData.setMsg(String.format("订单状态变化有误，订单号：{%s}，目前状态码：{%d}，新状态码：{%d}", orderNo, order.getOrderState(), orderState));
                    rtnData.setCode(ResultCode.ORDER_DRIVER_MARKED_PAIED);
                    rtnData.setMsg("司机代付订单，乘客不能支付");
                    return rtnData;
                }
                if (orderState < order.getOrderState()) {
                    rtnData.setCode(ResultCode.FAIL);
                    rtnData.setMsg(String.format("订单状态变化方向有误，订单号：{%s}，目前状态码：{%d}，新状态码：{%d}", orderNo, order.getOrderState(), orderState));
                    return rtnData;
                } else {
                    LOG.info(String.format("修改已入库的订单状态，订单【%s】状态从【%d】变成【%d】。", orderNo, order.getOrderState(), orderState));
                    order.setOrderState(orderState);
                    service.update(order);
                    oLogService.log(order, "数据库更新订单");
//                    rtnData.setCode(ResultCode.SUCCESS);
                    rtnData.setMsg("状态变更为:" + orderState);
                    return rtnData;
                }
            } else {
                rtnData.setCode(ResultCode.FAIL);
                rtnData.setMsg(String.format("未找到订单，订单号：{%s}", orderNo));
                return rtnData;
            }
        }
    }


    @ApiOperation(value = "司机 - 将订单标为司机代付", httpMethod = "POST", notes = "失败的话返回的data为订单当前状态，据此给用户进行提示")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "order_no", value = "订单编号", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class)
    })
    @PostMapping("markPaied")
    public ReturnData markPaied(@RequestParam(name = "order_no") String orderNo) {
        ReturnData rtnData = new ReturnData();
        int millisecond = 305000;// 305秒 多5秒钟避免同时发起支付
        // 一、先从redis中找订单
        Order order = service.getIngOrderByOrderNo(orderNo);
        //变更为司机代付的逻辑

        // 打印日志方便测试问题
        if (null != order) {
            String updateTime = DateFormatUtils.format(order.getUpdateTime(), "yyyy-MM-dd HH:mm:ss");
            LOG.info("updateTime = {}", updateTime);
            LOG.info("【订单时间毫秒】order.getUpdateTime().getTime() = {}", order.getUpdateTime().getTime());
            LOG.info("【当前时间毫秒】System.currentTimeMillis() = {}", System.currentTimeMillis());
            LOG.info("【订单状态】order.getOrderState() = {}", order.getOrderState());
            LOG.info("【当前时间毫秒-订单时间毫秒】System.currentTimeMillis()-order.getUpdateTime().getTime() = {}",
                    System.currentTimeMillis() - order.getUpdateTime().getTime());
        }
        // ----end-----

        if (order != null && (order.getOrderState().equals(OrderEnum.PENDING_PAY)
                || ((order.getOrderState().equals(OrderEnum.USER_PAYING)
                && (System.currentTimeMillis() - order.getUpdateTime().getTime() > millisecond))))) {
            //入库
            order.setMarkPaidTime(new Timestamp(System.currentTimeMillis()));
            order.setOrderState(OrderEnum.MARKED_PAIED);
            order.setPayType(OrderEnum.PAY_TYPE_DRIVER);
            service.paiedPersistence(order);
            //给乘客发送司机已代付消息
            OrderChangeMessage msg = new OrderChangeMessage(order.getOrderNo()
                    , OrderEnum.MARKED_PAIED, OrderChangeMessage.MESSAGE_TYPE_MARKED_PAIED, "已标为司机代付", order.getPlacingUserId());
            service.sendMqtt(JsonUtil.toString(msg)
                    , OrderEnum.ORDER_STATE_TOPIC + "." + order.getPlacingUserId());

            //发送支付成功消息给用户
            payService.sendAppPayMessage(order.getPlacingUserId(), order.getPlanDepartTime(),
                    Long.parseLong(String.valueOf(order.getFactFinalPrice())), order.getOrderType());
            /* 司机待支付放在redis里的老逻辑
            //1. redis.ORDER_STATUS 更新状态为代付款10(上面已处理)
            //2. 将 redis.ORDER_ING.pay_type 改为2
            order.setPayType(OrderEnum.PAY_TYPE_DRIVER);
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, order_no, JsonUtil.toString(order));
            //3. redis.ORDER_DRIVERS_PENDINGPAY 列表增加一条
            strRedisTemplate.opsForList().leftPush(Util.getDriverOrdersPendingPayKey(order.getDriverId()), order.getOrderNo());
            //4. redis.ORDERS_USER_PENDINGPAY 列表-1
            strRedisTemplate.opsForList().remove(Util.getUserOrdersPendingPayKey(order.getPlacingUserId()), 1, order.getOrderNo());
             */
            rtnData.setMsg("标记司机代付成功");
        } else {
            if (order == null) {
                rtnData.setMsg("订单已支付");
            } else {
                rtnData.setMsg("订单支付中");
            }
            rtnData.setCode(ResultCode.ORDER_DRIVER_MARK_PAIED_FAIL);
//            rtnData.setData(order.getOrderState().toString());
        }
        return rtnData;
    }


    @ApiOperation(value = "取消订单", httpMethod = "POST", notes = "取消类型, 1-乘客， 2-司机， 3-后台")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "order_no", value = "订单编号", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "cancel_type", value = "取消类型", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),

    })
    @PostMapping("cancelOrder")
    public ReturnData cancelOrder(@RequestParam(name = "order_no") String orderNo,
                                  @RequestParam(name = "cancel_type") Integer cancelType) {
        LOG.info(String.format("调用取消订单接口：订单号[%s]，类型[%d]", orderNo, cancelType));
        ReturnData returnData = new ReturnData();

        Order order = service.getIngOrderByOrderNo(orderNo);
        if (order != null) {

            if (order.getOrderState() >= OrderEnum.PASSENGER_GET_IN) {
                LOG.info(String.format("订单取消失败，当前订单的状态为[%s]，订单号[%s]。", order.getOrderState(), order.getOrderNo()));
                returnData.setCode(ResultCode.FAIL);
                returnData.setMsg("无法取消");
                return returnData;
            }

            order.setCancelTime(new Timestamp(System.currentTimeMillis()));
            order.setCancelType(cancelType);
            order.setCancelReason(OrderCancelTypeEnum.getEnum(cancelType).getMessage());
            order.setOrderState(OrderEnum.CANCEL_ORDER);
            order.setDestTime(new Timestamp(System.currentTimeMillis()));

            //取消订单数据持久化
            service.cancelOrderPersistence(order);

            String orderJson = JsonUtil.toString(order);
            LOG.info(String.format("订单取消成功发送MQ消息，订单号[%s]。", order.getOrderNo()));
            rabbitTemplate.convertAndSend(OrderEnum.ORDER_EXCHANGE, "kgcx.order.cancel", orderJson);

            // 给监管平台发消息
            LOG.info(String.format("订单取消成功给监管平台发MQ消息，订单号[%s]。", order.getOrderNo()));
            Message msg = Message.buildMessage(ApiContant.ORDER_CANCEL, Message.FLAG_ADD, order);
            rabbitTemplate.convertAndSend(ExchangeConst.OPC, RoutingKeyConst.OPC_COMMON, JSONObject.toJSONString(msg));

            if (order.getDriverId() != null && order.getDriverId() > 0) {
                //给司机发送mqtt消息
//                OrderChangeMessage message = new OrderChangeMessage(order.getOrderNo()
//                        , OrderEnum.MARKED_PAIED, OrderChangeMessage.MESSAGE_TYPE_CANCLE, "乘客已取消订单", order.getDriverId());
//                String topic = OrderEnum.ORDER_STATE_TOPIC + "." + order.getDriverId().toString();
                LOG.info(String.format("订单取消成功给司机发送消息，Order：[%s]。", JsonUtil.toString(order)));
//                service.sendMqtt(JsonUtil.toString(message), topic);
                orderNotifyDriverService.notifyDriver(order, "您的订单已被乘客取消");
            } else {
                LOG.info(String.format("订单【%s】取消成功，尚未派车所以不给司机发送消息。", order.getOrderNo()));
            }

        } else {
            LOG.info(String.format("订单【%s】未找到。", orderNo));
        }

        returnData.setCode(ResultCode.SUCCESS);
        returnData.setMsg("取消成功");
        return returnData;
    }


    @ApiOperation(value = "乘客 - 获取待处理订单(只返回订单号)", httpMethod = "GET", notes = "包含未支付和进行中的，未支付优先级高, 201-有未支付的订单， 202-有进行中的订单，个数根据data里的订单号个数判断")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "user_id", value = "下单人ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping("getIngOrder")
    @IdValidator("user_id")
    public ReturnData<String> getIngOrder(@RequestParam(name = "user_id") long userId) {
        String userOrdersPendingPayKey = Util.getUserOrdersPendingPayKey(userId);
        String userOrdersOngoingKey = Util.getUserOrdersOngoingKey(userId);
        String userOrdersPlanOngoingKey = Util.getUserOrdersPlanOngoingKey(userId);
        ReturnData<String> rtnData = new ReturnData<>();

        //1.1 检查是否有未支付订单
        long size = strRedisTemplate.opsForSet().size(userOrdersPendingPayKey);
        if (size > 0) {
            rtnData.setData(JsonUtil.toString(new ArrayList<>(strRedisTemplate.opsForSet().members(userOrdersPendingPayKey))));
            rtnData.setCode(ResultCode.HAS_ORDER_PENDING_PAY);
            rtnData.setMsg("有未支付订单");
            return rtnData;
        }

        //1.2 检查是否有未完成订单
        size = strRedisTemplate.opsForList().size(userOrdersOngoingKey);
        size += strRedisTemplate.opsForList().size(userOrdersPlanOngoingKey);
        int x = 0;
        //是否是 未完成订单不包含orderState=13、14、15、20的订单
        if (size > 0) {
            List<String> orderStrs = strRedisTemplate.opsForList().range(userOrdersOngoingKey, 0, -1);
            orderStrs.addAll(strRedisTemplate.opsForList().range(userOrdersPlanOngoingKey, 0, -1));
            Map<Object, Object> ordersMap = strRedisTemplate.opsForHash().entries(OrderEnum.ORDERS_ING);

            for (String orderKey : orderStrs) {
                Object obj = ordersMap.get(orderKey);
                if (obj == null) {
                    continue;
                }
                Order order = JsonUtil.toObject(obj.toString(), Order.class);
                if (order.getOrderState() == 13 || order.getOrderState() == 14 || order.getOrderState() == 15 || order.getOrderState() == 20) {
                    continue;
                } else {
                    x++;
                }
            }
        }

        //大于2单不可以继续下单
        if (x > 0) {
            List<String> orderStrs = strRedisTemplate.opsForList().range(userOrdersOngoingKey, 0, -1);
            orderStrs.addAll(strRedisTemplate.opsForList().range(userOrdersPlanOngoingKey, 0, -1));
            rtnData.setData(JsonUtil.toString(orderStrs));
            rtnData.setCode(ResultCode.HAS_ORDER_ONGOING);
            rtnData.setMsg("有进行中订单");
            return rtnData;
        }
        rtnData.setCode(ResultCode.SUCCESS);
        rtnData.setMsg("可以正常下单");
        return rtnData;
    }

    @ApiOperation(value = "司机 - 获取当日订单数、营业额", httpMethod = "GET", notes = "（入参：司机ID）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping("getDriverSummary")
    public ReturnData<OrderDriver> getDriverSummary() {
        RequestData rd = this.getRequestData();
        rd.put("date_day", DateTimeUtils.convertNumberDay(LocalDateTime.now()));
        return new ReturnData<>(odMapper.getTodayOrderDriver(rd));
    }

    @ApiOperation(value = "司机 - 检查司机是否能服务", httpMethod = "GET", notes = "（入参：司机ID）0-成功，可以接单，161054003 - 司机有代付订单未支付，不能继续服务")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping("checkDriverServeState")
    public ReturnData<Integer> checkDriverServeState(@RequestParam(name = "driver_id") Long driverId) {
        RequestData reqData = this.getRequestData();
        ReturnData<Integer> rtnData = new ReturnData<>();
        Calendar cal = Calendar.getInstance();
        Integer currHour = cal.get(Calendar.HOUR_OF_DAY);
        LOG.info("checkDriverServeState.当前时间小时数：" + currHour);
        Integer timeType = 2;
        if (currHour >= 0 && currHour < 5) {
            //如果现在是0:00-5:00点，判断昨日0点之前
//            reqData.put("time_type", 1);
            timeType = 1;
        } else {
            //如果现在是5:00-24:00点，判断今日0点之前
//            reqData.put("time_type", 2);
            timeType = 2;
        }

        LOG.info(String.format("checkDriverServeState.driver_id：{%d}, time_type: {%d}", driverId, timeType));
        Integer amount = service.getUnpayOrderCount(driverId, timeType);
        if (amount != null && amount > 0) {
            rtnData.setCode(ResultCode.ORDER_DRIVER_UNAVALIABLE);
            rtnData.setMsg("您有代付单尚未支付，暂时不能继续服务");
            rtnData.setData(amount);
        } else {
            rtnData.setCode(ResultCode.SUCCESS);
            rtnData.setMsg("您可以接单");
        }

        return rtnData;
    }

    @ApiOperation(value = "司机 - 按月查询营业额", httpMethod = "GET", notes = "（入参：年月、司机ID）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "date_month", value = "月份(示例：201711)", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
    })
    @GetMapping("getDriverTurnoverByMonth")
    public ReturnData<List<OrderDriver>> getDriverTurnoverByMonth() {
        RequestData rd = this.getRequestData();
        List<OrderDriver> lsOd = odMapper.listOrderDriver(rd);
        ReturnData<List<OrderDriver>> returnData = new ReturnData<>();
        returnData.setData(lsOd);
        return returnData;
    }

    @ApiOperation(value = "司机 - 查询年营业额", httpMethod = "GET", notes = "（入参：年、司机ID）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "date_year", value = "年份(示例：2017)", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
    })
    @GetMapping("getDriverAnnualSalesVolume")
    public ReturnData<Integer> getDriverAnnualSalesVolume(@RequestParam(name = "driver_id") Long driverId,
                                                          @RequestParam(name = "date_year") Integer dateYear) {
        RequestData rd = this.getRequestData();
        rd.put("date_day_from", Integer.valueOf(String.valueOf(dateYear) + "0101"));
        rd.put("date_day_to", Integer.valueOf(String.valueOf(dateYear) + "1230"));
        Integer amount = odMapper.getDriverAnnualSalesVolume(rd);
        ReturnData<Integer> returnData = new ReturnData<>();
        returnData.setData(amount);
        return returnData;
    }

    @ApiOperation(value = "内部调用 - 查询订单总金额", httpMethod = "GET", notes = "（下单人ID）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "user_id", value = "用户ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
    })
    @GetMapping("queryPaiedOrderAmount")
    public ReturnData<BigDecimal> queryPaiedOrderAmount(@RequestParam(name = "user_id") Long userId) {
        BigDecimal amount = service.queryPaiedOrderAmount(userId);
        ReturnData<BigDecimal> returnData = new ReturnData<>();
        returnData.setData(amount);
        return returnData;
    }

    @ApiOperation(value = "内部调用 - 查询所有可开票订单", httpMethod = "GET", notes = "（下单人ID）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "user_id", value = "用户ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
    })
    @GetMapping("queryPaiedOrderList")
    public ReturnData<List<String>> queryPaiedOrderList(@RequestParam(name = "user_id") Long userId) {
        List<String> ls = service.queryPaiedOrderList(userId);
        ReturnData<List<String>> returnData = new ReturnData<>();
        returnData.setData(ls);
        return returnData;
    }

    @ApiOperation(value = "司机 - 按月查询代付金额", httpMethod = "GET", notes = "（入参：年月、司机ID）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "date_month", value = "月份(示例：201711)", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
    })
    @GetMapping("getDriverPaiedByMonth")
    public ReturnData<List<OrderDriverPaied>> getDriverPaiedByMonth() {
        RequestData rd = this.getRequestData();
        List<OrderDriverPaied> lsOdp = odpMapper.listOrderDriverPaied(rd);
        ReturnData<List<OrderDriverPaied>> returnData = new ReturnData<>();
        returnData.setData(lsOdp);
        return returnData;
    }

    //司机 - 查询今天之前的未支付订单
    @ApiOperation(value = "司机 - 查询代付但是尚未支付的订单列表", httpMethod = "GET", notes = "（入参：司机ID）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping("listDriverPayingOrders")
    public ReturnData<List<DriverPayingOrder>> listDriverPayingOrders(
            @RequestParam(name = "driver_id") Long driverId) {
//        List<Order> lsResult = service.listDriverPayingOrders(requestData, driver_id);
        List<DriverPayingOrder> lsResult = service.queryDriverPayingOrder(driverId);
        ReturnData<List<DriverPayingOrder>> returnData = new ReturnData<>();
        returnData.setData(lsResult);
        return returnData;
    }

    @ApiOperation(value = "司机 - 根据司机ID查询服务中的订单", httpMethod = "GET", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping("getInServiceOrder4Driver")
    public ReturnData<Order> getInServiceOrder4Driver(@RequestParam(name = "driver_id") Long driverId) {
        ReturnData<Order> rtnData = new ReturnData<>();
        Order order = service.getDriverOrdersInService(driverId);
        if (order != null) {
//            rtnData.setCode(ResultCode.SUCCESS);
            rtnData.setData(order);
        } else {
//            rtnData.setCode(ResultCode.SUCCESS);
            rtnData.setMsg("该司机没有服务中的订单");
        }
        return rtnData;
    }


    @ApiOperation(value = "司机 - 开始行程", httpMethod = "POST", notes = "最终价格、里程数、状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "order_no", value = "订单号", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "dep_lng", value = "上车经度", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "dep_lat", value = "上车纬度", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "dep_orig", value = "上车位置", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "start_mile", value = "上车时里程表计数", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
    })
    @PostMapping("start")
    public ReturnData start(@RequestParam(name = "order_no") String orderNo,
                            @RequestParam(name = "dep_lng") String depLng,
                            @RequestParam(name = "dep_lat") String depLat,
                            @RequestParam(name = "dep_orig") String depOrig,
                            @RequestParam(name = "start_mile") Integer startMile) {

        ReturnData returnData = new ReturnData();
        String rtnMsg = "已开始行程"; //返回信息
        Object obj = strRedisTemplate.opsForHash().get(OrderEnum.ORDERS_ING, orderNo);

        if (obj != null) {

            Order order = JsonUtil.toObject(obj.toString(), Order.class);

            MileageRecord mileageRecord = new MileageRecord();
            mileageRecord.setStartMileage(startMile.longValue());
            mileageRecord.setDriverId(order.getDriverId().toString());
            mileageRecord.setOrderId(order.getOrderNo());
            mileageRecord.setCarId(order.getAutoId().toString());
            mileageLocationClient.recordStartMile(mileageRecord);


            order.setActualOrigLng(depLng);
            order.setActualOrigLat(depLat);
            order.setActualOrig(depOrig);
            order.setDepTime(new Timestamp(System.currentTimeMillis()));
            order.setStartMile(startMile);
            order.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            order.setOrderState(OrderEnum.ON_ROAD);
            //todo 立即用车空驶里程和空驶时间都为0，做预约的时候再加上相应逻辑
            order.setWaitMile(0);
            order.setWaitTime(0);

            String orderJson = JsonUtil.toString(order);

//            jsonRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, order_no, order);
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, orderNo, orderJson);
            strRedisTemplate.opsForHash()
                    .put(OrderEnum.ORDERS_STATUS, orderNo, String.valueOf(OrderEnum.ON_ROAD));

            // 给监管平台发消息
            Driver driver = driverClient.getDriver(order.getDriverId(), null);
            Order4Flat of = new Order4Flat();
            of.setOrder(order);
            of.setDriverLicenseId(driver.getLicenseId());
            of.setAutoNo(driver.getAutoNo());


            LOG.info(String.format("给监管平台发送经营出发的MQ消息，订单信息：【%s】。", JsonUtil.toString(of)));
            Message msg = Message.buildMessage(ApiContant.ORDER_DEPART, Message.FLAG_ADD, of);
            rabbitTemplate.convertAndSend(ExchangeConst.OPC, RoutingKeyConst.OPC_COMMON, JSONObject.toJSONString(msg));

//            rabbitTemplate.convertAndSend("kgcxOrder", OrderEnum.TO_DRIVER_ROUTING_KEY, orderJson);
            //发送行程开始的消息
            LOG.info(String.format("发送经营出发的MQ消息，订单信息：【%s】。", orderJson));
            rabbitTemplate.convertAndSend("kgcxOrder", OrderEnum.ROUTING_KEY_ORDER_START, orderJson);
            //todo 给乘客发消息、给司机发消息
            OrderChangeMessage mqMsg = new OrderChangeMessage(order.getOrderNo()
                    , OrderEnum.ON_ROAD, OrderChangeMessage.MESSAGE_TYPE_ON_ROAD, "开始行程", order.getPlacingUserId());
            service.sendMqtt(JsonUtil.toString(mqMsg)
                    , OrderEnum.ORDER_STATE_TOPIC + "." + order.getPlacingUserId());
        }

        returnData.setCode(ResultCode.SUCCESS);
        returnData.setMsg(rtnMsg);
        return returnData;
    }

    @ApiOperation(value = "司机 - 结束行程", httpMethod = "POST", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "order_no", value = "订单编号", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "lng", value = "目的地经度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "lat", value = "目的地维度", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "dest", value = "下车位置(例：中电软件园北门)", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "end_mile", value = "上车时里程表计数", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class)

    })
    @PostMapping("finishTravel")
    public ReturnData finishTravel(@RequestParam(name = "order_no") String orderNo,
                                   @RequestParam(required = true) String lng,
                                   @RequestParam(required = true) String lat,
                                   @RequestParam(required = true) String dest,
                                   @RequestParam(required = false, name = "end_mile") Integer endMile) {
        ReturnData rtnData = new ReturnData();
        Order order = service.getIngOrderByOrderNo(orderNo);

        MileageRecord mileageRecord = new MileageRecord();
        mileageRecord.setEndMileage(endMile.longValue());
        mileageRecord.setDriverId(order.getDriverId().toString());
        mileageRecord.setOrderId(order.getOrderNo());
        mileageRecord.setCarId(order.getAutoId().toString());
        mileageLocationClient.recordEndMile(mileageRecord);

        // 1. redis.ORDER_STATUS 更新状态为代付款9
        strRedisTemplate.opsForHash()
                .put(OrderEnum.ORDERS_STATUS, orderNo, String.valueOf(OrderEnum.ARRIVED_PENDING_PRICE));

        // 2. redis.ORDER_ING 更新相关字段
        order.setOrderState(OrderEnum.ARRIVED_PENDING_PRICE);
        order.setActualDestLng(lng);
        order.setActualDestLat(lat);
        order.setActualDest(dest);
        order.setEndMile(endMile);

        order.setDestTime(new Timestamp(System.currentTimeMillis()));


        String orderJson = JsonUtil.toString(order);
        strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, orderNo, orderJson);

        // 此处逻辑拿到UpdateListener里了



        //给乘客发送当前订单状态消息
        OrderChangeMessage mqMsg = new OrderChangeMessage(order.getOrderNo()
                , OrderEnum.ARRIVED_PENDING_PRICE, null, "finishTravel", order.getPlacingUserId());
        service.sendMqtt(JsonUtil.toString(mqMsg)
                , OrderEnum.ORDER_STATE_TOPIC + "." + order.getPlacingUserId());

        rtnData.setCode(ResultCode.SUCCESS);
        rtnData.setMsg("到达目的地，行程结束，等待司机填写最终里程并计算价格");
        return rtnData;
    }

    @PostMapping("finishOrder")
    public ReturnData finishOrder(@RequestParam(name = "order_no") String orderNo) {

        ReturnData rtnData = new ReturnData();
        Timestamp time = new Timestamp(System.currentTimeMillis());
        // 1. redis.ORDER_STATUS 更新状态为代付款9
        strRedisTemplate.opsForHash()
                .put(OrderEnum.ORDERS_STATUS, orderNo, String.valueOf(OrderEnum.PENDING_PAY));

        Order order = service.getIngOrderByOrderNo(orderNo);
        //判断用户待支付订单是否包含当前订单号，包含不执行操作
        if(!strRedisTemplate.opsForSet().isMember(Util.getUserOrdersPendingPayKey(order.getPlacingUserId()),order.getOrderNo())){
            if (order.getFactPrice() != null) {
                order.setOrderState(OrderEnum.PENDING_PAY);
                order.setUpdateTime(time);
                String orderJson = JsonUtil.toString(order);
                strRedisTemplate.opsForHash()
                        .put(OrderEnum.ORDERS_ING, order.getOrderNo(), orderJson);

                // 3. redis.ORDERS_USER_PENDINGPAY 列表+1
                service.addToUserOrdersPendingPay(order);

                // 4. redis.ORDERS_USER_ONGOING 列表-1
                service.removeFromUserOrdersOngoing(order);

                // 5.从司机服务中订单redis中删除
                service.removeFromDriverOrdersInService(order);

                //        String orderJson = JsonUtil.toString(order);

                // 6.给订阅者发送行程结束消息
                LOG.info(String.format("推送账单的MQ消息，订单信息：【%s】。", orderJson));
                rabbitTemplate.convertAndSend(OrderEnum.ORDER_EXCHANGE, OrderEnum.ROUTING_KEY_ORDER_PUSH_BILL, orderJson);

                // 6.修改司机状态
                LOG.info(String.format("推送账单的MQ消息，订单信息：【%s】。", orderJson));
                rabbitTemplate.convertAndSend(OrderEnum.ORDER_EXCHANGE, OrderEnum.ROUTING_KEY_ORDER_FINISH, orderJson);


                // 7.给监管平台发消息
                LOG.info(String.format("给监管平台发送经营到达的MQ消息，订单：[%s]。", orderJson));
                Message msg = Message.buildMessage(ApiContant.ORDER_ARRIVED, Message.FLAG_ADD, order);
                rabbitTemplate.convertAndSend(ExchangeConst.OPC, RoutingKeyConst.OPC_COMMON, JSONObject.toJSONString(msg));

                // 8.通知用户拉取账单信息
                String topic = OrderEnum.ORDER_STATE_TOPIC + "." + order.getPlacingUserId().toString();
                OrderChangeMessage mqMsg = new OrderChangeMessage(order.getOrderNo(), OrderEnum.PENDING_PAY,
                        OrderChangeMessage.MESSAGE_TYPE_DRAW_BILLS, "通知用户拉取账单", order.getPlacingUserId());
                service.sendMqtt(JsonUtil.toString(mqMsg), topic);

                LOG.info("推送账单：增加司机营业额：" + order.getFactFinalPrice());
                orderDriverService.add(order.getDriverId(), 1, order.getFactFinalPrice(), time);

                rtnData.setCode(ResultCode.SUCCESS);
                rtnData.setMsg("给乘客推送账单");
            } else {
                rtnData.setCode(ResultCode.FAIL);
                rtnData.setMsg("正在计算账单信息，请稍后再试");
            }
        }
        return rtnData;
    }

    //todo
    @ApiOperation(value = "查询乘客待支付订单列表", httpMethod = "GET", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderBy", value = "排序", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "user_id", value = "user_id", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping("queryUserPendingPay")
    public ReturnData<List<Order>> queryUserPendingPay(@RequestParam(name = "user_id") Long userId) {
        List<Order> list = service.listUserPendingPayOrder();
        ReturnData rtnData = new ReturnData();
        rtnData.setCode(ResultCode.SUCCESS);
        rtnData.setData(list);
        return rtnData;
    }

    @ApiOperation(value = "支付测试", httpMethod = "GET", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderNo", value = "排序", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)
    })
    @GetMapping("payTest")
    public ReturnData<Integer> payTest(@RequestParam String orderNo) {
        Order order = service.getIngOrderByOrderNo(orderNo);
        order.setDriverId(39L);
        order.setFactPrice(11);
        service.paiedPersistence(order);
        return new ReturnData<Integer>();
    }

    @ApiOperation(value = "通用 - 修改订单", httpMethod = "POST", notes = "传Order对象")
    @PostMapping("update")
    public ReturnData update(@RequestBody Order order) {
//        RequestData requestData = this.getRequestData();
        LOG.info("OrderController.update.order: " + JsonUtil.toString(order));
        service.update(order);
        return new ReturnData();
    }

    @ApiOperation(value = "orderClient测试", httpMethod = "GET", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderNo", value = "排序", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)
    })
    @GetMapping("orderClientTest")
    public ReturnData<Integer> orderClientTest(@RequestParam String orderNo) {
//        Order order = service.getIngOrderByOrderNo(orderNo);
        com.kgcx.common.client.order.pojo.Order order = new com.kgcx.common.client.order.pojo.Order();
        order.setOrderNo(orderNo);
        order.setOrderState(1111);
        orderClient.update(order);
        return new ReturnData<Integer>();
    }

//    @ApiOperation(value = "updateTest", httpMethod = "GET", notes = "")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "orderNo", value = "排序", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)
//    })
//    @GetMapping("updateTest")
//    public ReturnData<Integer> updateTest(@RequestParam String orderNo) {
//        Order order = service.getByOrderNo(orderNo);
//        order.setOrderState(1111);
//        this.update(order);
//        return new ReturnData<Integer>();
//    }


    @GetMapping("sendMqtt")
    public ReturnData sendMqtt(@RequestParam String payload,
                               @RequestParam String orderNo,
                               @RequestParam Integer orderState,
                               @RequestParam Long userId) {
        try {
            String topic = OrderEnum.ORDER_STATE_TOPIC + "." + userId.toString();
            OrderChangeMessage message = new OrderChangeMessage(orderNo, orderState,
                    OrderChangeMessage.MESSAGE_TYPE_CANCLE, payload, userId);
            service.sendMqtt(JsonUtil.toString(message), topic);
        } catch (Exception ex) {
            LOG.error("sendMqtt ex = " + ex.getMessage());
        }
        return new ReturnData();
    }

    @GetMapping("subscribeMqtt")
    public ReturnData subscribeMqtt(Long id) {
        LOG.info("begin subscribeMqtt");
        return service.subscribeMqtt(id);
    }

    @ApiImplicitParams({
            @ApiImplicitParam(name = "driver_id", value = "司机ID", required = true, paramType = "query", dataType = "Long", dataTypeClass = Long.class)

    })
    @ApiOperation(value = "测试 - 创建订单并派车成功", httpMethod = "POST", notes = "立即创建订单，返回订单号")
    @PostMapping("createTestOrder")
    public ReturnData<String> createTestOrder(@RequestParam(name = "driver_id") Long driverId) {

        Long placingUserId = 1L;
        String userOrdersPendingPayKey = Util.getUserOrdersPendingPayKey(placingUserId);
        String userOrdersOngoingKey = Util.getUserOrdersOngoingKey(placingUserId);
        ReturnData<String> returnData = new ReturnData<>();

//        //1.1 检查是否有未支付订单
//        long size = strRedisTemplate.opsForList().size(userOrdersPendingPayKey);
////        strRedisTemplate.opsForHash().get(OrderEnum.ORDERS_USER, userOrdersOngoingKey);
//        if (size >= 1) {
//            returnData.setData(strRedisTemplate.opsForList().index(userOrdersPendingPayKey, 0));
//            returnData.setCode(ResultCode.HAS_ORDER_PENDING_PAY);
//            returnData.setMsg("下单失败，有未支付的订单");
//            return returnData;
//        }
//
//        //1.2 检查是否有未完成订单
//        size = strRedisTemplate.opsForList().size(userOrdersOngoingKey);
//        if (size >= 2) { //大于2单不可以继续下单
//            returnData
//                    .setData(JsonUtil.toString(strRedisTemplate.opsForList().range(userOrdersOngoingKey, 0, -1)));
//            returnData.setCode(ResultCode.HAS_ORDER_ONGOING);
//            returnData.setMsg("下单失败，有超过两单未完成订单");
//            return returnData;
//        }

        //2.检查通过后继续下单流程
        Order record = new Order();
        try {
            record.setOrderNo(UUIDUtils.getOrderSnByTime18());
            record.setPlacingUserId(placingUserId);
            record.setPlacingUserPhone("13388889999");
            record.setPassengerPhone("13388889999");
            record.setIsSelf(1);
            record.setOrderChannel(1);
            record.setPlanOrigCityId(4301);
            record.setPlanOrig("黄花国际机场T1航站楼tt");
            record.setPlanOrigLng("22.00");
            record.setPlanOrigLat("33.00");
            record.setPlanDestCityId(0);
//            record.setPlanDest(URLDecoder.decode(plan_dest, "UTF-8"));
            record.setPlanDest("湖南大学tt");
            record.setPlanDestLng("22.02");
            record.setPlanDestLat("33.03");
            record.setPlanMileage(60000L);
            record.setPlanDuration(75);
            record.setPlanPrice(12000);
            record.setOrderType(1);
            record.setBookModel(1);
            record.setFareType(1);
            record.setPlanDepartTime(new Timestamp(System.currentTimeMillis()));
            record.setOrderState(OrderEnum.WAIT_ORDER);
            record.setCreateId(placingUserId);
            record.setCreateTime(new Timestamp(System.currentTimeMillis()));
            record.setStatus(Cons.COMMON_STATUS_ACTIVE);
            record.setPayType(OrderEnum.PAY_TYPE_USER); //默认乘客支付
            record.setAirportId(1L);
            record.setStationId(1L);

            record.setDriverId(driverId);
        } catch (Exception ex) {
            LOG.error("接受参数异常，ex=" + ex.getMessage());
        }

        String recordStr = JsonUtil.toString(record);
        try {
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_ING, record.getOrderNo(), recordStr);
            strRedisTemplate.opsForHash().put(OrderEnum.ORDERS_STATUS, record.getOrderNo(),
                    String.valueOf(record.getOrderState()));
            service.addToUserOrdersOngoing(record);
        } catch (Exception e) {
            e.printStackTrace();
        }

//        LOG.info(String.format("发送创建立即订单成功的消息，订单内容：[%s]。", JsonUtil.toString(record)));
//        rabbitTemplate.convertAndSend(OrderEnum.ORDER_EXCHANGE, "kgcx.order.create", recordStr);
//
//        // 给监管平台发消息
//        LOG.info(String.format("创建订单成功的MQ消息，订单号[%s]。", record.getOrderNo()));
//        Message msg = Message.buildMessage(ApiContant.ORDER_CREATE, Message.FLAG_ADD, record);
//        rabbitTemplate.convertAndSend(ExchangeConst.OPC, RoutingKeyConst.OPC_COMMON, JSONObject.toJSONString(msg));

        returnData.setData(record.getOrderNo());
        returnData.setCode(ResultCode.SUCCESS);
        returnData.setMsg("success");
        return returnData;
    }

    /**
     * 专给监管平台提供查询
     */
    @ApiOperation(value = "监管平台查询订单发起或撤销信息", httpMethod = "GET", notes = "这是用来给监管平台查询订单发起或撤销信息的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderBy", value = "排序,sql格式", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "orderState", value = "订单状态（1-等待接单，9-经营到达，13-已取消）", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderNo", value = "订单号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "autoNo", value = "车牌号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "driverName", value = "驾驶员姓名", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "driverPhone", value = "驾驶员电话", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)
    })
    @GetMapping("queryOrderCreatOrCancelWithPage")
    public ReturnData<List<Order>> queryOrderCreatOrCancelWithPage() {
        RequestData rd = this.getRequestData();
        List<Order> orderList = service.queryOrderWithPage(rd);
        return new ReturnData<>(orderList);
    }

    /**
     * 专给监管平台提供查询
     */
    @ApiOperation(value = "监管平台查询订单匹配成功或经营出发信息", httpMethod = "GET", notes = "这是用来给监管平台查询订单匹配成功或经营出发信息的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderBy", value = "排序,sql格式", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "orderState", value = "订单状态 3-订单成功，4-经营出发", required = true, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderNo", value = "订单号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "autoNo", value = "车牌号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "driverName", value = "驾驶员姓名", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "driverPhone", value = "驾驶员电话", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)
    })
    @GetMapping("queryOrderAndOperatWithPage")
    public ReturnData<List<Order>> queryOrderAndOperatWithPage() {
        RequestData rd = this.getRequestData();
        List<Order> orderList = service.queryBaseOrderWithPage(rd);
        return new ReturnData<>(orderList);
    }

    @ApiOperation(value = "根据前台传递条件查询进行中订单", httpMethod = "GET", notes = "这是用来根据前台传递条件查询进行中订单的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderNo", value = "订单号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "autoNo", value = "车牌号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "driverPhone", value = "驾驶员电话", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "placingUserPhone", value = "下单人", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "orderState", value = "订单状态", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class)
    })
    @GetMapping("queryOrderIngList")
    public ReturnData queryOrderIngList() {
        RequestData rd = this.getRequestData();
        rd.remove("COMMON_STATUS_ACTIVE");
        return service.getOrderIngList(rd);
    }


    @ApiOperation(value = "根据前台传递条件查询已完成订单", httpMethod = "GET", notes = "这是用来根据前台传递条件查询已完成订单的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderNoLike", value = "订单号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "placingUserPhoneLike", value = "下单人", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "autoNoLike", value = "车牌号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "driverPhoneLike", value = "司机电话", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "planOrigCityId", value = "城市", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderType", value = "服务类型", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "model", value = "车辆类型", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "payChannel", value = "支付类型", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderChannel", value = "订单来源", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderStateIn", value = "订单状态", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "createTimeBegin", value = "创建时间起始", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "createTimeEnd", value = "创建时间结束", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),

    })
    @GetMapping("getFinishOrderList")
    public ReturnData<List<Order>> getFinishOrderList() {
        List<Order> orderList = service.getFinishOrderList(this.getRequestData());
        return new ReturnData<>(orderList);
    }

    @ApiOperation(value = "根据前台传递条件导出excel已完成订单", httpMethod = "GET", notes = "这是用来根据前台传递条件导出excel已完成订单的接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderNoLike", value = "订单号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "placingUserPhoneLike", value = "下单人", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "autoNoLike", value = "车牌号", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "driverPhoneLike", value = "司机电话", required = false, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "planOrigCityId", value = "城市", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderType", value = "服务类型", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "model", value = "车辆类型", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "payChannel", value = "支付类型", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderChannel", value = "订单来源", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "orderStateIn", value = "订单状态", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "createTimeBegin", value = "创建时间起始", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "createTimeEnd", value = "创建时间结束", required = false, paramType = "query", dataType = "Long", dataTypeClass = Long.class),
    })
    @GetMapping("exportFinishOrderList")
    public ReturnData<String> exportFinishOrderList() throws IOException {
        RequestData rd = this.getRequestData();
        List<Order> orderList = dictService.buildDictValue(service.getFinishOrderList(rd));
        // 创建工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建工作表
        HSSFSheet sheet = workbook.createSheet("sheet1");
        HSSFRow row1 = sheet.createRow(0);
        row1.createCell(0).setCellValue("订单编号");
        row1.createCell(1).setCellValue("司机");
        row1.createCell(2).setCellValue("车牌");
        row1.createCell(3).setCellValue("订单创建时间");
        row1.createCell(4).setCellValue("用时(分)");
        row1.createCell(5).setCellValue("出发地");
        row1.createCell(6).setCellValue("目的地");
        row1.createCell(7).setCellValue("里程(公里)");
        row1.createCell(8).setCellValue("支付价格(元)");
        row1.createCell(9).setCellValue("乘客电话");
        row1.createCell(10).setCellValue("支付方");
        row1.createCell(11).setCellValue("支付方式");

        for (int i = 0; i < orderList.size(); i++) {
            HSSFRow rows = sheet.createRow(i + 1);
            Order order = orderList.get(i);
            // 向工作表中添加数据
            rows.createCell(0).setCellValue(order.getOrderNo());
            rows.createCell(1).setCellValue(order.getDriverName());
            rows.createCell(2).setCellValue(order.getAutoNo());
            rows.createCell(3).setCellValue(DateUtil.format(order.getCreateTime(), DatePattern.NORM_DATETIME_PATTERN));
            rows.createCell(4).setCellValue(order.getDriveTime() == null ? "" : String.valueOf(order.getDriveTime() / 60));
            rows.createCell(5).setCellValue(order.getActualOrig());
            rows.createCell(6).setCellValue(order.getActualDest());
            rows.createCell(7).setCellValue(order.getDriveMile() == null ? "" : String.valueOf(order.getDriveMile() / 1000));
            rows.createCell(8).setCellValue(order.getFactFinalPrice() == null ? "" : String.valueOf(order.getFactFinalPrice() / 100));
            rows.createCell(9).setCellValue(order.getPassengerPhone());
            rows.createCell(10).setCellValue(order.getPayTypeValue());
            rows.createCell(11).setCellValue(order.getPayChannelValue());
        }

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        workbook.write(bos);

        String fileName = MD5Util.MD5Encode(rd.toString(), StandardCharsets.UTF_8.name()) + ".xls";
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType("application/vnd.ms-excel");
        FileUtils.uploadFile(FileUtils.ossFileBucket, fileName, new ByteArrayInputStream(bos.toByteArray()), meta);
        return new ReturnData<>(fileName);
    }


    @ApiOperation(value = "查询用户里程", httpMethod = "GET")
    @GetMapping("queryUserMileage")
    public ReturnData<HashMap<Long, UserMileage>> queryUserMileage(List<Long> userIds) {
        HashMap<Long, UserMileage> data = service.queryUserMileage(userIds);
        ReturnData<HashMap<Long, UserMileage>> rtn = new ReturnData<>();
        rtn.setData(data);
        return rtn;
    }

    @ApiOperation(value = "查询热门地址", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "cityId", value = "城市id", required = true, paramType = "query", dataType = "long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
    })
    @GetMapping("getHotAddress")
    public ReturnData<List<HotAddress>> getHotAddress(Long cityId, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<HotAddress> list = service.getHotAddress(cityId);
        return new ReturnData<>(list);
    }

    @ApiOperation(value = "查询热门城市", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "cityId", value = "城市id", required = true, paramType = "query", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "pageNum", value = "页码", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页容量", required = false, paramType = "query", dataType = "int", dataTypeClass = Integer.class),
    })
    @GetMapping("getHotCity")
    public ReturnData<List<Region>> getHotCity(Long cityId) {
        return new ReturnData<>(service.getHotCity(cityId));
    }

    @GetMapping("test")
    public ReturnData test() {
        List<Long> userIds = new ArrayList<>(Arrays.asList(1L, 10L, 13L, 126L, 128L, 999L));

        service.queryUserMileage(userIds);
//        service.queryUserMonthlyMileage(userIds);
        return new ReturnData();
    }

    // 计算完附加费之后修改redis中数据
    @GetMapping("updateRedis")
    public ReturnData updateRedis(String json) {
        LOG.info("订单 - 状态变更：json=" + json);
        //JSONObject jsonObject = JSONObject.parseObject(json);
        //获取并解析消息
        PriceActualPrice pap = JsonUtil.toObject(json, PriceActualPrice.class);
//        计算完价格暂时不需要更改订单状态为待支付
//        strRedisTemplate.opsForHash()
//                .put(OrderEnum.ORDERS_STATUS, pap.getOrderId(),
//                        String.valueOf(OrderEnum.PENDING_PAY));

        Order order = service.getIngOrderByOrderNo(pap.getOrderId());

        if (order != null) {
            // 1.redis.ORDERS_ING 中更新价格(含优惠券的价格)、里程、优惠券信息
            order.setFactPrice(pap.getTotalMoney() == null ? null : pap.getTotalMoney().intValue());
            order.setFactFinalPrice(pap.getTotalFee() == null ? null : pap.getTotalFee().intValue());
            order.setDriveMile(pap.getMileage() == null ? null : pap.getMileage().intValue());
            if (pap.getCouponId() != null) {
                order.setCouponId(pap.getCouponId().intValue());
                couponClient.updateCouponState(pap.getCouponId(), Coupon.STATE_USING);
            }
            order.setDriveTime(pap.getTime());
//            order.setOrderState(OrderEnum.PENDING_PAY);
            order.setDestTime(new Timestamp(System.currentTimeMillis()));

            String orderJson = JsonUtil.toString(order);
            strRedisTemplate.opsForHash()
                    .put(OrderEnum.ORDERS_ING, order.getOrderNo(), orderJson);
        }
        return new ReturnData();
    }
}
